/*
 * InstrUtils.h
 *
 *  Created on: 2011-8-1
 *      Author: gexiao
 */
/*
 * Dalvik instruction utility functions.
 */
#ifndef INSTRUTILS_H_
#define INSTRUTILS_H_

#include "DexFile.h"
#include "OpCode.h"

/*
 * Dalvik-defined instruction formats.
 *
 * (This defines InstructionFormat as an unsigned char to reduce the size
 * of the table. This isn't necessary with some compilers, which use an
 * integer width appropriate for the number of enum values.)
 *
 * If you add or delete a format, you have to change some or all of:
 *  - this enum
 *  - the switch inside dexDecodeInstruction() in InstrUtils.c
 *  - the switch inside dumpInstruction() in DexDump.c
 */
typedef unsigned char InstructionFormat;
enum InstructionFormat {
	kFmtUnknown = 0, kFmt10x, // op
	kFmt12x, // op vA, vB
	kFmt11n, // op vA, #+B
	kFmt11x, // op vAA
	kFmt10t, // op +AA
	kFmt20t, // op +AAAA
	kFmt22x, // op vAA, vBBBB
	kFmt21t, // op vAA, +BBBB
	kFmt21s, // op vAA, #+BBBB
	kFmt21h, // op vAA, #+BBBB00000[00000000]
	kFmt21c, // op vAA, thing@BBBB
	kFmt23x, // op vAA, vBB, vCC
	kFmt22b, // op vAA, vBB, #+CC
	kFmt22t, // op vA, vB, +CCCC
	kFmt22s, // op vA, vB, #+CCCC
	kFmt22c, // op vA, vB, thing@CCCC
	kFmt22cs, // [opt] op vA, vB, field offset CCCC
	kFmt32x, // op vAAAA, vBBBB
	kFmt30t, // op +AAAAAAAA
	kFmt31t, // op vAA, +BBBBBBBB
	kFmt31i, // op vAA, #+BBBBBBBB
	kFmt31c, // op vAA, thing@BBBBBBBB
	kFmt35c, // op {vC, vD, vE, vF, vG}, thing@BBBB (B: count, A: vG)
	kFmt35ms, // [opt] invoke-virtual+super
	kFmt35fs, // [opt] invoke-interface
	kFmt3rc, // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
	kFmt3rms, // [opt] invoke-virtual+super/range
	kFmt3rfs, // [opt] invoke-interface/range
	kFmt3inline, // [opt] inline invoke
	kFmt51l,
// op vAA, #+BBBBBBBBBBBBBBBB
};

/*
 * Instruction width, a value in the range -3 to 5.
 */
typedef signed char InstructionWidth;

/*
 * Instruction flags, used by the verifier to determine where control
 * can flow to next.
 */
typedef unsigned char InstructionFlags;
enum InstructionFlags {
	kInstrCanBranch = 1, // conditional or unconditional branch
	kInstrCanContinue = 1 << 1, // flow can continue to next statement
	kInstrCanSwitch = 1 << 2, // switch statement
	kInstrCanThrow = 1 << 3, // could cause an exception to be thrown
	kInstrCanReturn = 1 << 4,
// returns, no additional statements
};

/*
 * Allocate and populate a 256-element array with instruction widths.  A
 * width of zero means the entry does not exist.
 */
InstructionWidth* dexCreateInstrWidthTable(void);

/*
 * Returns the width of the specified instruction, or 0 if not defined.
 * Optimized instructions use negative values.
 */
DEX_INLINE int dexGetInstrWidth(const InstructionWidth* widths, OpCode opCode) {
	return widths[opCode];
}

/*
 * Return the width of the specified instruction, or 0 if not defined.
 */
DEX_INLINE int dexGetInstrWidthAbs(const InstructionWidth* widths,
		OpCode opCode) {
	int val = dexGetInstrWidth(widths, opCode);
	if (val < 0)
		val = -val;
	return val;
}

/*
 * Allocate and populate a 256-element array with instruction flags.
 */
InstructionFlags* dexCreateInstrFlagsTable(void);

/*
 * Allocate and populate a 256-element array with instruction formats.
 */
InstructionFormat* dexCreateInstrFormatTable(void);
#endif /* INSTRUTILS_H_ */
